package xyz.ssf.cloud.project.system.service.impl;

import com.google.code.kaptcha.Producer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import xyz.ssf.cloud.common.utils.JwtUtil;
import xyz.ssf.cloud.common.utils.PasswordUtil;
import xyz.ssf.cloud.common.utils.RedisUtil;
import xyz.ssf.cloud.project.system.domain.SysLoginLog;
import xyz.ssf.cloud.project.system.domain.SysUser;
import xyz.ssf.cloud.project.system.domain.vo.LoginRequestVo;
import xyz.ssf.cloud.project.system.domain.vo.LoginUserVo;
import xyz.ssf.cloud.project.system.domain.vo.PasswordUpdateVO;
import xyz.ssf.cloud.project.system.domain.vo.ProfileUpdateVO;
import xyz.ssf.cloud.project.system.mapper.SysUserMapper;
import xyz.ssf.cloud.project.system.service.ISysLoginLogService;
import xyz.ssf.cloud.project.system.service.ISysLoginService;
import xyz.ssf.cloud.project.system.service.ISysUserService;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 登录校验方法
 * 
 * @author ssf
 */
@Service
public class SysLoginServiceImpl implements ISysLoginService {
    
    @Autowired
    private ISysUserService userService;
    
    @Autowired
    private ISysLoginLogService loginLogService;
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private Producer captchaProducer;
    
    // 验证码Redis前缀
    private static final String CAPTCHA_CODE_KEY = "captcha_codes:";
    
    // 登录用户Redis前缀
    private static final String LOGIN_TOKEN_KEY = "login_tokens:";
    
    // 登录失败次数Redis前缀
    private static final String LOGIN_FAIL_KEY = "login_fail:";
    
    // 登录失败最大次数
    private static final int MAX_FAIL_COUNT = 5;
    
    // 登录锁定时间（分钟）
    private static final int LOCK_TIME = 30;
    
    // 开发阶段固定验证码
    @Value("${system.captcha.dev-captcha:1234}")
    private String devCaptcha;
    
    // 是否使用开发模式验证码
    @Value("${system.captcha.use-dev-captcha:false}")
    private boolean useDevCaptcha;

    /**
     * 登录验证
     * 
     * @param loginRequest 登录信息
     * @return 结果
     */
    @Override
    public String login(LoginRequestVo loginRequest) {
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();
        String code = loginRequest.getCode();
        String uuid = loginRequest.getUuid();
        
        // 校验参数
        if (StringUtils.isAnyBlank(username, password, code, uuid)) {
            throw new RuntimeException("登录参数不能为空");
        }
        
        // 检查用户是否被锁定
        String failKey = LOGIN_FAIL_KEY + username;
        Integer failCount = redisUtil.getCacheObject(failKey);
        if (failCount != null && failCount >= MAX_FAIL_COUNT) {
            throw new RuntimeException("密码错误次数过多，账户已被锁定" + LOCK_TIME + "分钟");
        }
        
        // 校验验证码
        if (useDevCaptcha) {
            // 开发阶段使用固定验证码
            if (!devCaptcha.equalsIgnoreCase(code)) {
                throw new RuntimeException("验证码错误");
            }
        } else {
            // 生产环境正常校验验证码
            String captchaKey = CAPTCHA_CODE_KEY + uuid;
            String captcha = redisUtil.getCacheObject(captchaKey);
            redisUtil.deleteObject(captchaKey);
            if (captcha == null) {
                throw new RuntimeException("验证码已过期，请重新获取");
            }
            if (!code.equalsIgnoreCase(captcha)) {
                throw new RuntimeException("验证码错误");
            }
        }
        
        // 查询用户
        SysUser user = userService.selectUserByUsername(username);
        if (user == null) {
            recordLoginFail(username);
            throw new RuntimeException("用户名或密码错误");
        }
        
        // 判断用户状态
        if ("1".equals(user.getStatus())) {
            throw new RuntimeException("账号已停用，请联系管理员");
        }
        
        // 校验密码
        if (!PasswordUtil.matches(password, user.getPassword())) {
            recordLoginFail(username);
            throw new RuntimeException("用户名或密码错误");
        }
        
        // 清除登录失败记录
        redisUtil.deleteObject(failKey);
        
        // 记录登录信息
        recordLoginInfo(user);
        
        // 生成token
        String token = jwtUtil.generateToken(user.getId());
        
        // 创建登录用户对象
        LoginUserVo loginUser = createLoginUser(user);
        loginUser.setToken(token);
        
        // 缓存登录用户
        String userKey = LOGIN_TOKEN_KEY + token;
        redisUtil.setCacheObject(userKey, loginUser, (long) jwtUtil.getExpireTime(), TimeUnit.HOURS);
        
        return token;
    }

    /**
     * 获取用户信息
     * 
     * @return 用户信息
     */
    @Override
    public LoginUserVo getLoginUser() {
        // 获取请求头中的token
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(jwtUtil.getHeader());
        
        if (StringUtils.isBlank(token)) {
            throw new RuntimeException("未提供token");
        }
        
        // 处理Bearer前缀
        String tokenValue = token;
        if (token.startsWith("Bearer ")) {
            tokenValue = token.substring(7);
            System.out.println("处理了用户信息中的Bearer前缀");
        }
        
        // 验证token有效性
        if (!jwtUtil.validateToken(tokenValue)) {
            throw new RuntimeException("token已过期或无效");
        }
        
        // 从Redis获取用户信息
        String userKey = LOGIN_TOKEN_KEY + tokenValue;
        LoginUserVo loginUser = redisUtil.getCacheObject(userKey);
        
        if (loginUser == null) {
            throw new RuntimeException("登录状态已过期");
        }
        
        return loginUser;
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {
        // 获取请求头中的token
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(jwtUtil.getHeader());
        
        if (StringUtils.isNotBlank(token)) {
            // 处理Bearer前缀
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
                System.out.println("处理了退出登录中的Bearer前缀");
            }
            
            // 删除Redis中的用户信息
            String userKey = LOGIN_TOKEN_KEY + token;
            redisUtil.deleteObject(userKey);
        }
    }

    /**
     * 获取验证码
     * 
     * @return 验证码信息
     */
    @Override
    public Object getCaptcha() {
        // 生成验证码
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String verifyCode;
        
        if (useDevCaptcha) {
            // 开发阶段使用固定验证码
            verifyCode = devCaptcha;
        } else {
            // 生产环境生成随机验证码
            verifyCode = captchaProducer.createText();
            // 将验证码存入Redis，有效期2分钟
            redisUtil.setCacheObject(CAPTCHA_CODE_KEY + uuid, verifyCode, 2L, TimeUnit.MINUTES);
        }
        
        // 生成验证码图片
        BufferedImage image = captchaProducer.createImage(verifyCode);
        
        try {
            // 将图片转为Base64编码
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", stream);
            String base64Image = Base64.getEncoder().encodeToString(stream.toByteArray());
            
            // 返回验证码信息
            Map<String, String> result = new HashMap<>();
            result.put("uuid", uuid);
            result.put("img", base64Image);
            
            return result;
        } catch (Exception e) {
            throw new RuntimeException("验证码生成失败");
        }
    }
    
    /**
     * 记录登录失败次数
     * 
     * @param username 用户名
     */
    private void recordLoginFail(String username) {
        String failKey = LOGIN_FAIL_KEY + username;
        Integer failCount = redisUtil.getCacheObject(failKey);
        failCount = failCount == null ? 1 : failCount + 1;
        
        // 如果达到最大失败次数，设置锁定时间
        if (failCount >= MAX_FAIL_COUNT) {
            redisUtil.setCacheObject(failKey, failCount, (long) LOCK_TIME, TimeUnit.MINUTES);
        } else {
            redisUtil.setCacheObject(failKey, failCount, 24L, TimeUnit.HOURS);
        }
    }
    
    /**
     * 记录登录信息
     * 
     * @param user 用户信息
     */
    private void recordLoginInfo(SysUser user) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = getIpAddr(request);
        
        // 更新用户登录信息
        user.setLoginIp(ip);
        userService.updateLoginInfo(user);
        
        // 记录登录日志
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setUsername(user.getUsername());
        loginLog.setIpAddr(ip);
        loginLog.setLoginLocation("内网IP"); // 可以添加IP地址解析逻辑获取地理位置
        loginLog.setBrowser(getBrowser(request));
        loginLog.setOs(getOs(request));
        loginLog.setStatus("0"); // 登录成功
        loginLog.setMsg("登录成功");
        loginLog.setLoginTime(new Date());
        loginLogService.insertLoginLog(loginLog);
    }
    
    /**
     * 获取请求中的浏览器类型
     * 
     * @param request 请求对象
     * @return 浏览器类型
     */
    private String getBrowser(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        if (userAgent == null) {
            return "未知浏览器";
        }
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            return "IE浏览器";
        } else if (userAgent.contains("Firefox")) {
            return "Firefox浏览器";
        } else if (userAgent.contains("Chrome")) {
            return "Chrome浏览器";
        } else if (userAgent.contains("Safari")) {
            return "Safari浏览器";
        } else {
            return "其他浏览器";
        }
    }
    
    /**
     * 获取请求中的操作系统
     * 
     * @param request 请求对象
     * @return 操作系统
     */
    private String getOs(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        if (userAgent == null) {
            return "未知操作系统";
        }
        if (userAgent.contains("Windows")) {
            return "Windows";
        } else if (userAgent.contains("Mac")) {
            return "Mac OS";
        } else if (userAgent.contains("Linux")) {
            return "Linux";
        } else if (userAgent.contains("Android")) {
            return "Android";
        } else if (userAgent.contains("iOS") || userAgent.contains("iPhone")) {
            return "iOS";
        } else {
            return "其他操作系统";
        }
    }
    
    /**
     * 创建登录用户对象
     * 
     * @param user 用户信息
     * @return 登录用户对象
     */
    @Override
    public LoginUserVo createLoginUser(SysUser user) {
        LoginUserVo loginUser = new LoginUserVo();
        
        // 设置用户信息
        loginUser.setUser(user);
        
        // 设置角色和权限
        if (user != null) {
            // 获取用户角色
            String[] roles = userService.getUserRoles(user.getId());
            loginUser.setRoles(roles);
            
            // 获取用户权限
            String[] permissions = userService.getUserPermissions(user.getId());
            loginUser.setPermissions(permissions);
        }
        
        return loginUser;
    }
    
    /**
     * 获取IP地址
     * 
     * @param request 请求
     * @return IP地址
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    /**
     * 生成token
     * 
     * @param param 参数
     * @return token
     */
    @Override
    public String generateToken(Map<String, Object> param) {
        // 从参数中获取userId
        Object userId = param.get("userId");
        if (userId == null) {
            throw new RuntimeException("用户ID不能为空");
        }
        
        Long id = Long.valueOf(userId.toString());
        
        // 生成token
        String token = jwtUtil.generateToken(id);
        
        // 创建一个简单的登录用户对象，只包含必要信息
        LoginUserVo loginUser = new LoginUserVo();
        loginUser.setToken(token);
        
        // 缓存登录用户
        String userKey = LOGIN_TOKEN_KEY + token;
        System.out.println("缓存用户信息，键: " + userKey);
        redisUtil.setCacheObject(userKey, loginUser, (long) jwtUtil.getExpireTime(), TimeUnit.HOURS);
        
        return token;
    }
} 